home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 October / maximum-cd-2009-10.iso / DiscContents / Firefox Setup 3.5.exe / nonlocalized / chrome / toolkit.jar / content / global / customizeToolbar.js < prev    next >
Encoding:
Text File  |  2009-06-24  |  27.5 KB  |  935 lines

  1. //@line 40 "e:\builds\moz2_slave\win32_build\build\toolkit\content\customizeToolbar.js"
  2.  
  3. const kRowMax = 4;
  4.  
  5. var gToolboxDocument = null;
  6. var gToolbox = null;
  7. var gCurrentDragOverItem = null;
  8. var gToolboxChanged = false;
  9. var gToolboxIconSize = false;
  10. var gToolboxSheet = false;
  11.  
  12. function onLoad()
  13. {
  14.   if ("arguments" in window && window.arguments[0]) {
  15.     InitWithToolbox(window.arguments[0]);
  16.     repositionDialog();
  17.   }
  18.   else if (window.frameElement &&
  19.            "toolbox" in window.frameElement) {
  20.     gToolboxSheet = true;
  21.     InitWithToolbox(window.frameElement.toolbox);
  22.   }
  23. }
  24.  
  25. function InitWithToolbox(aToolbox)
  26. {
  27.   gToolbox = aToolbox;
  28.   gToolboxDocument = gToolbox.ownerDocument;
  29.   gToolbox.customizing = true;
  30.  
  31.   gToolbox.addEventListener("dragstart", onToolbarDragStart, false);
  32.   gToolbox.addEventListener("dragover", onToolbarDragOver, false);
  33.   gToolbox.addEventListener("dragleave", onToolbarDragLeave, false);
  34.   gToolbox.addEventListener("drop", onToolbarDrop, false);
  35.  
  36.   initDialog();
  37. }
  38.  
  39. function onClose()
  40. {
  41.   if (!gToolboxSheet)
  42.     window.close();
  43.   else
  44.     finishToolbarCustomization();
  45. }
  46.  
  47. function onUnload()
  48. {
  49.   if (!gToolboxSheet)
  50.     finishToolbarCustomization();
  51. }
  52.  
  53. function finishToolbarCustomization()
  54. {
  55.   gToolbox.customizing = false;
  56.   removeToolboxListeners();
  57.   unwrapToolbarItems();
  58.   persistCurrentSets();
  59.   
  60.   notifyParentComplete();
  61. }
  62.  
  63. function initDialog()
  64. {
  65.   var mode = gToolbox.getAttribute("mode");
  66.   document.getElementById("modelist").value = mode;
  67.   gToolboxIconSize = gToolbox.getAttribute("iconsize");
  68.   var smallIconsCheckbox = document.getElementById("smallicons");
  69.   smallIconsCheckbox.checked = gToolboxIconSize == "small";
  70.   if (mode == "text")
  71.     smallIconsCheckbox.disabled = true;
  72.  
  73.   // Build up the palette of other items.
  74.   buildPalette();
  75.  
  76.   // Wrap all the items on the toolbar in toolbarpaletteitems.
  77.   wrapToolbarItems();
  78. }
  79.  
  80. function repositionDialog()
  81. {
  82.   // Position the dialog touching the bottom of the toolbox and centered with 
  83.   // it.
  84.   var width;
  85.   if (document.documentElement.hasAttribute("width"))
  86.     width = document.documentElement.getAttribute("width");
  87.   else
  88.     width = parseInt(document.documentElement.style.width);
  89.   var screenX = gToolbox.boxObject.screenX 
  90.                 + ((gToolbox.boxObject.width - width) / 2);
  91.   var screenY = gToolbox.boxObject.screenY + gToolbox.boxObject.height;
  92.  
  93.   window.moveTo(screenX, screenY);
  94. }
  95.  
  96. function removeToolboxListeners()
  97. {
  98.   gToolbox.removeEventListener("dragstart", onToolbarDragStart, false);
  99.   gToolbox.removeEventListener("dragover", onToolbarDragOver, false);
  100.   gToolbox.removeEventListener("dragleave", onToolbarDragLeave, false);
  101.   gToolbox.removeEventListener("drop", onToolbarDrop, false);
  102. }
  103.  
  104. /**
  105.  * Invoke a callback on the toolbox to notify it that the dialog is done
  106.  * and going away.
  107.  */
  108. function notifyParentComplete()
  109. {
  110.   if ("customizeDone" in gToolbox)
  111.     gToolbox.customizeDone(gToolboxChanged);
  112. }
  113.  
  114. function toolboxChanged(aEvent)
  115. {
  116.   gToolboxChanged = true;
  117.   if ("customizeChange" in gToolbox)
  118.     gToolbox.customizeChange(aEvent);
  119. }
  120.  
  121. function getToolbarAt(i)
  122. {
  123.   return gToolbox.childNodes[i];
  124. }
  125.  
  126. /**
  127.  * Persist the current set of buttons in all customizable toolbars to
  128.  * localstore.
  129.  */
  130. function persistCurrentSets()
  131. {
  132.   if (!gToolboxChanged || gToolboxDocument.defaultView.closed)
  133.     return;
  134.  
  135.   var customCount = 0;
  136.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  137.     // Look for customizable toolbars that need to be persisted.
  138.     var toolbar = getToolbarAt(i);
  139.     if (isCustomizableToolbar(toolbar)) {
  140.       // Calculate currentset and store it in the attribute.
  141.       var currentSet = toolbar.currentSet;
  142.       toolbar.setAttribute("currentset", currentSet);
  143.       
  144.       var customIndex = toolbar.hasAttribute("customindex");
  145.       if (customIndex) {
  146.         if (!toolbar.firstChild) {
  147.           // Remove custom toolbars whose contents have been removed.
  148.           gToolbox.removeChild(toolbar);
  149.           --i;
  150.         } else {
  151.           // Persist custom toolbar info on the <toolbarset/>
  152.           gToolbox.toolbarset.setAttribute("toolbar"+(++customCount),
  153.                                            toolbar.toolbarName + ":" + currentSet);
  154.           gToolboxDocument.persist(gToolbox.toolbarset.id, "toolbar"+customCount);
  155.         }
  156.       }
  157.  
  158.       if (!customIndex) {
  159.         // Persist the currentset attribute directly on hardcoded toolbars.
  160.         gToolboxDocument.persist(toolbar.id, "currentset");
  161.       }
  162.     }
  163.   }
  164.   
  165.   // Remove toolbarX attributes for removed toolbars.
  166.   while (gToolbox.toolbarset.hasAttribute("toolbar"+(++customCount))) {
  167.     gToolbox.toolbarset.removeAttribute("toolbar"+customCount);
  168.     gToolboxDocument.persist(gToolbox.toolbarset.id, "toolbar"+customCount);
  169.   }
  170. }
  171.  
  172. /**
  173.  * Wraps all items in all customizable toolbars in a toolbox.
  174.  */
  175. function wrapToolbarItems()
  176. {
  177.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  178.     var toolbar = getToolbarAt(i);
  179.     if (isCustomizableToolbar(toolbar)) {
  180.       for (var k = 0; k < toolbar.childNodes.length; ++k) {
  181.         var item = toolbar.childNodes[k];
  182.  
  183. //@line 225 "e:\builds\moz2_slave\win32_build\build\toolkit\content\customizeToolbar.js"
  184.  
  185.         if (isToolbarItem(item)) {
  186.           var wrapper = wrapToolbarItem(item);
  187.           cleanupItemForToolbar(item, wrapper);
  188.         }
  189.       }
  190.     }
  191.   }
  192. }
  193.  
  194. /**
  195.  * Unwraps all items in all customizable toolbars in a toolbox.
  196.  */
  197. function unwrapToolbarItems()
  198. {
  199.   var paletteItems = gToolbox.getElementsByTagName("toolbarpaletteitem");
  200.   var paletteItem;
  201.   while ((paletteItem = paletteItems.item(0)) != null) {
  202.     var toolbarItem = paletteItem.firstChild;
  203.  
  204.     if (paletteItem.hasAttribute("itemdisabled"))
  205.       toolbarItem.disabled = true;
  206.  
  207.     if (paletteItem.hasAttribute("itemcommand"))
  208.       toolbarItem.setAttribute("command", paletteItem.getAttribute("itemcommand"));
  209.  
  210.     paletteItem.parentNode.replaceChild(toolbarItem, paletteItem);
  211.   }
  212. }
  213.  
  214. /**
  215.  * Creates a wrapper that can be used to contain a toolbaritem and prevent
  216.  * it from receiving UI events.
  217.  */
  218. function createWrapper(aId, aDocument)
  219. {
  220.   var wrapper = aDocument.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  221.                                          "toolbarpaletteitem");
  222.  
  223.   wrapper.id = "wrapper-"+aId;  
  224.   return wrapper;
  225. }
  226.  
  227. /**
  228.  * Wraps an item that has been cloned from a template and adds
  229.  * it to the end of a row in the palette.
  230.  */
  231. function wrapPaletteItem(aPaletteItem, aCurrentRow, aSpacer)
  232. {
  233.   var wrapper = createWrapper(aPaletteItem.id, document);
  234.  
  235.   wrapper.setAttribute("flex", 1);
  236.   wrapper.setAttribute("align", "center");
  237.   wrapper.setAttribute("pack", "center");
  238.   wrapper.setAttribute("minheight", "0");
  239.   wrapper.setAttribute("minwidth", "0");
  240.  
  241.   wrapper.appendChild(aPaletteItem);
  242.   
  243.   // XXX We need to call this AFTER the palette item has been appended
  244.   // to the wrapper or else we crash dropping certain buttons on the 
  245.   // palette due to removal of the command and disabled attributes - JRH
  246.   cleanUpItemForPalette(aPaletteItem, wrapper);
  247.  
  248.   if (aSpacer)
  249.     aCurrentRow.insertBefore(wrapper, aSpacer);
  250.   else
  251.     aCurrentRow.appendChild(wrapper);
  252.  
  253. }
  254.  
  255. /**
  256.  * Wraps an item that is currently on a toolbar and replaces the item
  257.  * with the wrapper. This is not used when dropping items from the palette,
  258.  * only when first starting the dialog and wrapping everything on the toolbars.
  259.  */
  260. function wrapToolbarItem(aToolbarItem)
  261. {
  262.   var wrapper = createWrapper(aToolbarItem.id, gToolboxDocument);
  263.  
  264.   wrapper.flex = aToolbarItem.flex;
  265.  
  266.   aToolbarItem.parentNode.replaceChild(wrapper, aToolbarItem);
  267.   
  268.   wrapper.appendChild(aToolbarItem);
  269.   
  270.   return wrapper;
  271. }
  272.  
  273. /**
  274.  * Get the list of ids for the current set of items on each toolbar.
  275.  */
  276. function getCurrentItemIds()
  277. {
  278.   var currentItems = {};
  279.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  280.     var toolbar = getToolbarAt(i);
  281.     if (isCustomizableToolbar(toolbar)) {
  282.       var child = toolbar.firstChild;
  283.       while (child) {
  284.         if (isToolbarItem(child))
  285.           currentItems[child.id] = 1;
  286.         child = child.nextSibling;
  287.       }
  288.     }
  289.   }
  290.   return currentItems;
  291. }
  292.  
  293. /**
  294.  * Builds the palette of draggable items that are not yet in a toolbar.
  295.  */
  296. function buildPalette()
  297. {
  298.   // Empty the palette first.
  299.   var paletteBox = document.getElementById("palette-box");
  300.   while (paletteBox.lastChild)
  301.     paletteBox.removeChild(paletteBox.lastChild);
  302.  
  303.   var currentRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  304.                                             "hbox");
  305.   currentRow.setAttribute("class", "paletteRow");
  306.  
  307.   // Add the toolbar separator item.
  308.   var templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  309.                                               "toolbarseparator");
  310.   templateNode.id = "separator";
  311.   wrapPaletteItem(templateNode, currentRow, null);
  312.  
  313.   // Add the toolbar spring item.
  314.   templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  315.                                               "toolbarspring");
  316.   templateNode.id = "spring";
  317.   templateNode.flex = 1;
  318.   wrapPaletteItem(templateNode, currentRow, null);
  319.  
  320.   // Add the toolbar spacer item.
  321.   templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  322.                                               "toolbarspacer");
  323.   templateNode.id = "spacer";
  324.   templateNode.flex = 1;
  325.   wrapPaletteItem(templateNode, currentRow, null);
  326.  
  327.   var rowSlot = 3;
  328.  
  329.   var currentItems = getCurrentItemIds();
  330.   templateNode = gToolbox.palette.firstChild;
  331.   while (templateNode) {
  332.     // Check if the item is already in a toolbar before adding it to the palette.
  333.     if (!(templateNode.id in currentItems)) {
  334.       var paletteItem = document.importNode(templateNode, true);
  335.  
  336.       if (rowSlot == kRowMax) {
  337.         // Append the old row.
  338.         paletteBox.appendChild(currentRow);
  339.  
  340.         // Make a new row.
  341.         currentRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  342.                                               "hbox");
  343.         currentRow.setAttribute("class", "paletteRow");
  344.         rowSlot = 0;
  345.       }
  346.  
  347.       ++rowSlot;
  348.       wrapPaletteItem(paletteItem, currentRow, null);
  349.     }
  350.     
  351.     templateNode = templateNode.nextSibling;
  352.   }
  353.  
  354.   if (currentRow) { 
  355.     fillRowWithFlex(currentRow);
  356.     paletteBox.appendChild(currentRow);
  357.   }
  358. }
  359.  
  360. /**
  361.  * Creates a new palette item for a cloned template node and
  362.  * adds it to the last slot in the palette.
  363.  */
  364. function appendPaletteItem(aItem)
  365. {
  366.   var paletteBox = document.getElementById("palette-box");
  367.   var lastRow = paletteBox.lastChild;
  368.   var lastSpacer = lastRow.lastChild;
  369.    
  370.   if (lastSpacer.localName != "spacer") {
  371.     // The current row is full, so we have to create a new row.
  372.     lastRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  373.                                         "hbox");
  374.     lastRow.setAttribute("class", "paletteRow");
  375.     paletteBox.appendChild(lastRow);
  376.     
  377.     wrapPaletteItem(aItem, lastRow, null);
  378.  
  379.     fillRowWithFlex(lastRow);
  380.   } else {
  381.     // Decrement the flex of the last spacer or remove it entirely.
  382.     var flex = lastSpacer.getAttribute("flex");
  383.     if (flex == 1) {
  384.       lastRow.removeChild(lastSpacer);
  385.       lastSpacer = null;
  386.     } else
  387.       lastSpacer.setAttribute("flex", --flex);
  388.  
  389.     // Insert the wrapper where the last spacer was.
  390.     wrapPaletteItem(aItem, lastRow, lastSpacer);
  391.   }
  392. }
  393.  
  394. function fillRowWithFlex(aRow)
  395. {
  396.   var remainingFlex = kRowMax - aRow.childNodes.length;
  397.   if (remainingFlex > 0) {
  398.     var spacer = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  399.                                           "spacer");
  400.     spacer.setAttribute("flex", remainingFlex);
  401.     aRow.appendChild(spacer);
  402.   }
  403. }
  404.  
  405. /**
  406.  * Makes sure that an item that has been cloned from a template
  407.  * is stripped of all properties that may adversely affect its
  408.  * appearance in the palette.
  409.  */
  410. function cleanUpItemForPalette(aItem, aWrapper)
  411. {
  412.   aWrapper.setAttribute("place", "palette");
  413.   setWrapperType(aItem, aWrapper);
  414.  
  415.   if (aItem.hasAttribute("title"))
  416.     aWrapper.setAttribute("title", aItem.getAttribute("title"));
  417.   else if (isSpecialItem(aItem)) {
  418.     var stringBundle = document.getElementById("stringBundle");
  419.     // Remove the common "toolbar" prefix to generate the string name.
  420.     var title = stringBundle.getString(aItem.localName.slice(7) + "Title");
  421.     aWrapper.setAttribute("title", title);
  422.   }
  423.   
  424.   // Remove attributes that screw up our appearance.
  425.   aItem.removeAttribute("command");
  426.   aItem.removeAttribute("observes");
  427.   aItem.removeAttribute("disabled");
  428.   aItem.removeAttribute("type");
  429.   aItem.removeAttribute("width");
  430.   
  431.   if (aItem.localName == "toolbaritem" && aItem.firstChild) {
  432.     aItem.firstChild.removeAttribute("observes");
  433.  
  434.     // So the throbber doesn't throb in the dialog,
  435.     // cute as that may be...
  436.     aItem.firstChild.removeAttribute("busy");
  437.   }
  438. }
  439.  
  440. /**
  441.  * Makes sure that an item that has been cloned from a template
  442.  * is stripped of all properties that may adversely affect its
  443.  * appearance in the toolbar.  Store critical properties on the 
  444.  * wrapper so they can be put back on the item when we're done.
  445.  */
  446. function cleanupItemForToolbar(aItem, aWrapper)
  447. {
  448.   setWrapperType(aItem, aWrapper);
  449.   aWrapper.setAttribute("place", "toolbar");
  450.  
  451.   if (aItem.hasAttribute("command")) {
  452.     aWrapper.setAttribute("itemcommand", aItem.getAttribute("command"));
  453.     aItem.removeAttribute("command");
  454.   }
  455.  
  456.   if (aItem.disabled) {
  457.     aWrapper.setAttribute("itemdisabled", "true");
  458.     aItem.disabled = false;
  459.   }
  460. }
  461.  
  462. function setWrapperType(aItem, aWrapper)
  463. {
  464.   if (aItem.localName == "toolbarseparator") {
  465.     aWrapper.setAttribute("type", "separator");
  466.   } else if (aItem.localName == "toolbarspring") {
  467.     aWrapper.setAttribute("type", "spring");
  468.   } else if (aItem.localName == "toolbarspacer") {
  469.     aWrapper.setAttribute("type", "spacer");
  470.   } else if (aItem.localName == "toolbaritem" && aItem.firstChild) {
  471.     aWrapper.setAttribute("type", aItem.firstChild.localName);
  472.   }
  473. }
  474.  
  475. function setDragActive(aItem, aValue)
  476. {
  477.   var node = aItem;
  478.   var direction = window.getComputedStyle(aItem, null).direction;
  479.   var value = direction == "ltr"? "left" : "right";
  480.   if (aItem.localName == "toolbar") {
  481.     node = aItem.lastChild;
  482.     value = direction == "ltr"? "right" : "left";
  483.   }
  484.   
  485.   if (!node)
  486.     return;
  487.   
  488.   if (aValue) {
  489.     if (!node.hasAttribute("dragover"))
  490.       node.setAttribute("dragover", value);
  491.   } else {
  492.     node.removeAttribute("dragover");
  493.   }
  494. }
  495.  
  496. function addNewToolbar()
  497. {
  498.   var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  499.                                 .getService(Components.interfaces.nsIPromptService);
  500.  
  501.   var stringBundle = document.getElementById("stringBundle");
  502.   var message = stringBundle.getString("enterToolbarName");
  503.   var title = stringBundle.getString("enterToolbarTitle");
  504.  
  505.   var name = {};
  506.  
  507.   // Quitting from the toolbar dialog while the new toolbar prompt is up
  508.   // can cause things to become unresponsive on the Mac. Until dialog modality
  509.   // is fixed (395465), disable the "Done" button explicitly.
  510.   var doneButton = document.getElementById("donebutton");
  511.   doneButton.disabled = true;
  512.  
  513.   while (true) {
  514.  
  515.     if (!promptService.prompt(window, title, message, name, null, {})) {
  516.       doneButton.disabled = false;
  517.       return;
  518.     }
  519.     
  520.     if (!name.value) {
  521.       message = stringBundle.getFormattedString("enterToolbarBlank", [name.value]);
  522.       continue;
  523.     }
  524.  
  525.     var dupeFound = false;
  526.  
  527.      // Check for an existing toolbar with the same display name
  528.     for (i = 0; i < gToolbox.childNodes.length; ++i) {
  529.       var toolbar = gToolbox.childNodes[i];
  530.       var toolbarName = toolbar.getAttribute("toolbarname");
  531.  
  532.       if (toolbarName == name.value &&
  533.           toolbar.getAttribute("type") != "menubar" &&
  534.           toolbar.nodeName == 'toolbar') {
  535.         dupeFound = true;
  536.         break;
  537.       }
  538.     }
  539.  
  540.     if (!dupeFound)
  541.       break;
  542.  
  543.     message = stringBundle.getFormattedString("enterToolbarDup", [name.value]);
  544.   }
  545.     
  546.   gToolbox.appendCustomToolbar(name.value, "");
  547.   
  548.   toolboxChanged();
  549.  
  550.   doneButton.disabled = false;
  551. }
  552.  
  553. /**
  554.  * Restore the default set of buttons to fixed toolbars,
  555.  * remove all custom toolbars, and rebuild the palette.
  556.  */
  557. function restoreDefaultSet()
  558. {
  559.   // Unwrap the items on the toolbar.
  560.   unwrapToolbarItems();
  561.  
  562.   // Remove all of the customized toolbars.
  563.   var child = gToolbox.lastChild;
  564.   while (child) {
  565.     if (child.hasAttribute("customindex")) {
  566.       var thisChild = child;
  567.       child = child.previousSibling;
  568.       thisChild.currentSet = "__empty";
  569.       gToolbox.removeChild(thisChild);
  570.     } else {
  571.       child = child.previousSibling;
  572.     }
  573.   }
  574.  
  575.   // Restore the defaultset for fixed toolbars.
  576.   var toolbar = gToolbox.firstChild;
  577.   while (toolbar) {
  578.     if (isCustomizableToolbar(toolbar)) {
  579.       var defaultSet = toolbar.getAttribute("defaultset");
  580.       if (defaultSet)
  581.         toolbar.currentSet = defaultSet;
  582.     }
  583.     toolbar = toolbar.nextSibling;
  584.   }
  585.  
  586.   // Restore the default icon size and mode.
  587.   var defaultMode = gToolbox.getAttribute("defaultmode");
  588.   var defaultIconsSmall = gToolbox.getAttribute("defaulticonsize") == "small";
  589.  
  590.   updateIconSize(defaultIconsSmall, true);
  591.   document.getElementById("smallicons").checked = defaultIconsSmall;
  592.   updateToolbarMode(defaultMode, true);
  593.   document.getElementById("modelist").value = defaultMode;
  594.  
  595.   // Now rebuild the palette.
  596.   buildPalette();
  597.  
  598.   // Now re-wrap the items on the toolbar.
  599.   wrapToolbarItems();
  600.  
  601.   toolboxChanged("reset");
  602. }
  603.  
  604. function updateIconSize(aUseSmallIcons, localDefault)
  605. {
  606.   gToolboxIconSize = aUseSmallIcons ? "small" : "large";
  607.   
  608.   setAttribute(gToolbox, "iconsize", gToolboxIconSize);
  609.   gToolboxDocument.persist(gToolbox.id, "iconsize");
  610.   
  611.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  612.     var toolbar = getToolbarAt(i);
  613.     if (isCustomizableToolbar(toolbar)) {
  614.       var toolbarIconSize = (localDefault && toolbar.hasAttribute("defaulticonsize")) ?
  615.                             toolbar.getAttribute("defaulticonsize") :
  616.                             gToolboxIconSize;
  617.       setAttribute(toolbar, "iconsize", toolbarIconSize);
  618.       gToolboxDocument.persist(toolbar.id, "iconsize");
  619.     }
  620.   }
  621. }
  622.  
  623. function updateToolbarMode(aModeValue, localDefault)
  624. {
  625.   setAttribute(gToolbox, "mode", aModeValue);
  626.   gToolboxDocument.persist(gToolbox.id, "mode");
  627.  
  628.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  629.     var toolbar = getToolbarAt(i);
  630.     if (isCustomizableToolbar(toolbar)) {
  631.       var toolbarMode = (localDefault && toolbar.hasAttribute("defaultmode")) ?
  632.                         toolbar.getAttribute("defaultmode") :
  633.                         aModeValue;
  634.       setAttribute(toolbar, "mode", toolbarMode);
  635.       gToolboxDocument.persist(toolbar.id, "mode");
  636.     }
  637.   }
  638.  
  639.   var iconSizeCheckbox = document.getElementById("smallicons");
  640.   iconSizeCheckbox.disabled = aModeValue == "text";
  641. }
  642.  
  643.  
  644. function setAttribute(aElt, aAttr, aVal)
  645. {
  646.  if (aVal)
  647.     aElt.setAttribute(aAttr, aVal);
  648.   else
  649.     aElt.removeAttribute(aAttr);
  650. }
  651.  
  652. function isCustomizableToolbar(aElt)
  653. {
  654.   return aElt.localName == "toolbar" &&
  655.          aElt.getAttribute("customizable") == "true";
  656. }
  657.  
  658. function isSpecialItem(aElt)
  659. {
  660.   return aElt.localName == "toolbarseparator" ||
  661.          aElt.localName == "toolbarspring" ||
  662.          aElt.localName == "toolbarspacer";
  663. }
  664.  
  665. function isToolbarItem(aElt)
  666. {
  667.   return aElt.localName == "toolbarbutton" ||
  668.          aElt.localName == "toolbaritem" ||
  669.          aElt.localName == "toolbarseparator" ||
  670.          aElt.localName == "toolbarspring" ||
  671.          aElt.localName == "toolbarspacer";
  672. }
  673.  
  674. ///////////////////////////////////////////////////////////////////////////
  675. //// Drag and Drop observers
  676.  
  677. function onToolbarDragStart(aEvent)
  678. {
  679.   nsDragAndDrop.startDrag(aEvent, dragStartObserver);
  680. }
  681.  
  682. function onToolbarDragOver(aEvent)
  683. {
  684.   nsDragAndDrop.dragOver(aEvent, toolbarDNDObserver);
  685. }
  686.  
  687. function onToolbarDrop(aEvent)
  688. {
  689.   nsDragAndDrop.drop(aEvent, toolbarDNDObserver);
  690. }
  691.  
  692. function onToolbarDragLeave(aEvent)
  693. {
  694.   if (gCurrentDragOverItem)
  695.     setDragActive(gCurrentDragOverItem, false);
  696. }
  697.  
  698. var dragStartObserver =
  699. {
  700.   onDragStart: function (aEvent, aXferData, aDragAction) {
  701.     var documentId = gToolboxDocument.documentElement.id;
  702.     
  703.     var item = aEvent.target;
  704.     while (item && item.localName != "toolbarpaletteitem")
  705.       item = item.parentNode;
  706.     
  707.     item.setAttribute("dragactive", "true");
  708.     
  709.     aXferData.data = new TransferDataSet();
  710.     var data = new TransferData();
  711.     data.addDataForFlavour("text/toolbarwrapper-id/"+documentId, item.firstChild.id);
  712.     aXferData.data.push(data);
  713.     aDragAction.action = Components.interfaces.nsIDragService.DRAGDROP_ACTION_MOVE;
  714.   }
  715. }
  716.  
  717. var toolbarDNDObserver =
  718. {
  719.   onDragOver: function (aEvent, aFlavour, aDragSession)
  720.   {
  721.     var toolbar = aEvent.target;
  722.     var dropTarget = aEvent.target;
  723.     while (toolbar && toolbar.localName != "toolbar") {
  724.       dropTarget = toolbar;
  725.       toolbar = toolbar.parentNode;
  726.     }
  727.     
  728.     var previousDragItem = gCurrentDragOverItem;
  729.  
  730.     // Make sure we are dragging over a customizable toolbar.
  731.     if (!isCustomizableToolbar(toolbar)) {
  732.       gCurrentDragOverItem = null;
  733.       return;
  734.     }
  735.     
  736.     if (dropTarget.localName == "toolbar") {
  737.       gCurrentDragOverItem = dropTarget;
  738.     } else {
  739.       gCurrentDragOverItem = null;
  740.  
  741.       var direction = window.getComputedStyle(dropTarget.parentNode, null).direction;
  742.       var dropTargetCenter = dropTarget.boxObject.x + (dropTarget.boxObject.width / 2);
  743.       if (direction == "ltr")
  744.         dragAfter = aEvent.clientX > dropTargetCenter;
  745.       else
  746.         dragAfter = aEvent.clientX < dropTargetCenter;
  747.         
  748.       if (dragAfter) {
  749.         gCurrentDragOverItem = dropTarget.nextSibling;
  750.         if (!gCurrentDragOverItem)
  751.           gCurrentDragOverItem = toolbar;
  752.       } else
  753.         gCurrentDragOverItem = dropTarget;
  754.     }    
  755.  
  756.     if (previousDragItem && gCurrentDragOverItem != previousDragItem) {
  757.       setDragActive(previousDragItem, false);
  758.     }
  759.     
  760.     setDragActive(gCurrentDragOverItem, true);
  761.     
  762.     aDragSession.canDrop = true;
  763.   },
  764.   
  765.   onDrop: function (aEvent, aXferData, aDragSession)
  766.   {
  767.     if (!gCurrentDragOverItem)
  768.       return;
  769.     
  770.     setDragActive(gCurrentDragOverItem, false);
  771.  
  772.     var draggedItemId = aXferData.data;
  773.     if (gCurrentDragOverItem.id == draggedItemId)
  774.       return;
  775.  
  776.     var toolbar = aEvent.target;
  777.     while (toolbar.localName != "toolbar")
  778.       toolbar = toolbar.parentNode;
  779.  
  780.     var draggedPaletteWrapper = document.getElementById("wrapper-"+draggedItemId);       
  781.     if (!draggedPaletteWrapper) {
  782.       // The wrapper has been dragged from the toolbar.
  783.       
  784.       // Get the wrapper from the toolbar document and make sure that
  785.       // it isn't being dropped on itself.
  786.       var wrapper = gToolboxDocument.getElementById("wrapper-"+draggedItemId);
  787.       if (wrapper == gCurrentDragOverItem)
  788.         return;
  789.  
  790.       // Don't allow static kids (e.g., the menubar) to move.
  791.       if (wrapper.parentNode.firstPermanentChild && wrapper.parentNode.firstPermanentChild.id == wrapper.firstChild.id)
  792.         return;
  793.       if (wrapper.parentNode.lastPermanentChild && wrapper.parentNode.lastPermanentChild.id == wrapper.firstChild.id)
  794.         return;
  795.  
  796.       // Remove the item from its place in the toolbar.
  797.       wrapper.parentNode.removeChild(wrapper);
  798.  
  799.       // Determine which toolbar we are dropping on.
  800.       var dropToolbar = null;
  801.       if (gCurrentDragOverItem.localName == "toolbar")
  802.         dropToolbar = gCurrentDragOverItem;
  803.       else
  804.         dropToolbar = gCurrentDragOverItem.parentNode;
  805.       
  806.       // Insert the item into the toolbar.
  807.       if (gCurrentDragOverItem != dropToolbar)
  808.         dropToolbar.insertBefore(wrapper, gCurrentDragOverItem);
  809.       else
  810.         dropToolbar.appendChild(wrapper);
  811.     } else {
  812.       // The item has been dragged from the palette
  813.       
  814.       // Create a new wrapper for the item. We don't know the id yet.
  815.       var wrapper = createWrapper("", gToolboxDocument);
  816.  
  817.       // Ask the toolbar to clone the item's template, place it inside the wrapper, and insert it in the toolbar.
  818.       var newItem = toolbar.insertItem(draggedItemId, gCurrentDragOverItem == toolbar ? null : gCurrentDragOverItem, wrapper);
  819.       
  820.       // Prepare the item and wrapper to look good on the toolbar.
  821.       cleanupItemForToolbar(newItem, wrapper);
  822.       wrapper.id = "wrapper-"+newItem.id;
  823.       wrapper.flex = newItem.flex;
  824.  
  825.       // Remove the wrapper from the palette.
  826.       var currentRow = draggedPaletteWrapper.parentNode;
  827.       if (draggedItemId != "separator" &&
  828.           draggedItemId != "spring" &&
  829.           draggedItemId != "spacer")
  830.       {
  831.         currentRow.removeChild(draggedPaletteWrapper);
  832.  
  833.         while (currentRow) {
  834.           // Pull the first child of the next row up
  835.           // into this row.
  836.           var nextRow = currentRow.nextSibling;
  837.           
  838.           if (!nextRow) {
  839.             var last = currentRow.lastChild;
  840.             var first = currentRow.firstChild;
  841.             if (first == last) {
  842.               // Kill the row.
  843.               currentRow.parentNode.removeChild(currentRow);
  844.               break;
  845.             }
  846.  
  847.             if (last.localName == "spacer") {
  848.               var flex = last.getAttribute("flex");
  849.               last.setAttribute("flex", ++flex);
  850.               // Reflow doesn't happen for some reason.  Trigger it with a hide/show. ICK! -dwh
  851.               last.hidden = true;
  852.               last.hidden = false;
  853.               break;
  854.             } else {
  855.               // Make a spacer and give it a flex of 1.
  856.               var spacer = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  857.                                                     "spacer");
  858.               spacer.setAttribute("flex", "1");
  859.               currentRow.appendChild(spacer);
  860.             }
  861.             break;
  862.           }
  863.           
  864.           currentRow.appendChild(nextRow.firstChild);
  865.           currentRow = currentRow.nextSibling;
  866.         }
  867.       }
  868.     }
  869.     
  870.     gCurrentDragOverItem = null;
  871.  
  872.     toolboxChanged();
  873.   },
  874.   
  875.   _flavourSet: null,
  876.   
  877.   getSupportedFlavours: function ()
  878.   {
  879.     if (!this._flavourSet) {
  880.       this._flavourSet = new FlavourSet();
  881.       var documentId = gToolboxDocument.documentElement.id;
  882.       this._flavourSet.appendFlavour("text/toolbarwrapper-id/"+documentId);
  883.     }
  884.     return this._flavourSet;
  885.   }
  886. }
  887.  
  888. var paletteDNDObserver =
  889. {
  890.   onDragOver: function (aEvent, aFlavour, aDragSession)
  891.   {
  892.     aDragSession.canDrop = true;
  893.   },
  894.   
  895.   onDrop: function(aEvent, aXferData, aDragSession)
  896.   {
  897.     var itemId = aXferData.data;
  898.     
  899.     var wrapper = gToolboxDocument.getElementById("wrapper-"+itemId);
  900.     if (wrapper) {
  901.       // Don't allow static kids (e.g., the menubar) to move.
  902.       if (wrapper.parentNode.firstPermanentChild && wrapper.parentNode.firstPermanentChild.id == wrapper.firstChild.id)
  903.         return;
  904.       if (wrapper.parentNode.lastPermanentChild && wrapper.parentNode.lastPermanentChild.id == wrapper.firstChild.id)
  905.         return;
  906.  
  907.       var wrapperType = wrapper.getAttribute("type");
  908.       if (wrapperType != "separator" &&
  909.           wrapperType != "spacer" &&
  910.           wrapperType != "spring") {
  911.         appendPaletteItem(document.importNode(wrapper.firstChild, true));
  912.         gToolbox.palette.appendChild(wrapper.firstChild);
  913.       }
  914.  
  915.       // The item was dragged out of the toolbar.
  916.       wrapper.parentNode.removeChild(wrapper);
  917.     }
  918.     
  919.     toolboxChanged();
  920.   },
  921.   
  922.   _flavourSet: null,
  923.   
  924.   getSupportedFlavours: function ()
  925.   {
  926.     if (!this._flavourSet) {
  927.       this._flavourSet = new FlavourSet();
  928.       var documentId = gToolboxDocument.documentElement.id;
  929.       this._flavourSet.appendFlavour("text/toolbarwrapper-id/"+documentId);
  930.     }
  931.     return this._flavourSet;
  932.   }
  933. }
  934.  
  935.